/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#include "NodeCpp/Data/Rel/SqlConnectionFactory.h"
#include "NodeCpp/LockGuard.h"
#include "NodeCpp/Data/Rel/SqlConnectionFactoryImpl.h"

namespace NodeCpp {
namespace Data {
namespace Rel {

    SqlConnectionFactory::SqlConnectionFactory(void)
        : Factories_()
        , FactoriesLock_()
    {

    }

    SqlConnectionFactory::~SqlConnectionFactory(void)
    {
        _Uninitialize();
    }

    void SqlConnectionFactory::RegistryFactory(const std::string& _Key, SqlConnectionFactoryImpl* _Factory)
    {
        Instance()._RegistryFactory(_Key, _Factory);
    }

    void SqlConnectionFactory::UnregistryFactory(const std::string& _Key)
    {
        Instance()._UnregistryFactory(_Key);
    }

    SqlConnection* SqlConnectionFactory::Create(Session* _Sess, const std::string& _Key, 
        const std::string& _Host, const std::string& _Port, const std::string& _User, 
        const std::string _Password, const std::string& _Db)
    {
        SqlConnectionFactoryImpl* _FactoryImpl = Instance()._FindFactory(_Key);
        NODECPP_ASSERT(_FactoryImpl);
        if (_FactoryImpl) {
            return _FactoryImpl->Create(_Sess, _Host, _Port, _User, _Password, _Db);
        }
        return NULL;
    }

    void SqlConnectionFactory::_RegistryFactory(const std::string& _Key, SqlConnectionFactoryImpl* _Factory)
    {
        NODECPP_LOCK_MUTEX(_Guard, FactoriesLock_);
        std::deque<struct _FactoryEntry>::iterator _Iter = Factories_.begin();
        for (; _Iter != Factories_.end(); ++_Iter) {
            if (_Iter->Key == _Key) {
                NODECPP_ASSERT(false);
                return;
            }
        }

        struct _FactoryEntry _Entry;
        _Entry.Key = _Key;
        _Entry.Factory = _Factory;
        Factories_.push_back(_Entry);
    }

    void SqlConnectionFactory::_UnregistryFactory(const std::string& _Key)
    {
        NODECPP_LOCK_MUTEX(_Guard, FactoriesLock_);
        std::deque<struct _FactoryEntry>::iterator _Iter = Factories_.begin();
        for (; _Iter != Factories_.end(); ++_Iter) {
            if (_Iter->Key == _Key) {
                /* Delete factory */
                delete _Iter->Factory;
                Factories_.erase(_Iter);
                break;
            }
        }
    }

    SqlConnectionFactoryImpl* SqlConnectionFactory::_FindFactory(const std::string& _Key)
    {
        NODECPP_LOCK_MUTEX(_Guard, FactoriesLock_);
        std::deque<struct _FactoryEntry>::iterator _Iter = Factories_.begin();
        for (; _Iter != Factories_.end(); ++_Iter) {
            if (_Iter->Key == _Key) {
                return _Iter->Factory;
            }
        }
        return NULL;
    }

    void SqlConnectionFactory::_Uninitialize(void)
    {
        while (!Factories_.empty())
        {
            delete Factories_.front().Factory;
            Factories_.pop_front();
        }
    }

}}}